/*
 * Equipment.cpp
 *
 *  Created on: Jun 16, 2012
 *      Author: gonzalo
 */

#include "UserEquipment.h"
#include "ButtonListItem.h"
#include "equipment/EquipmentMissile.h"
#include "equipment/EquipmentBullets.h"
#include "equipment/EquipmentUserInfo.h"
#include "equipment/EquipmentBasicShield.h"
#include "equipment/EquipmentSuperShield.h"
#include "equipment/EquipmentInvisible.h"
#include "equipment/EquipmentMina.h"
#include "equipment/EquipmentLaser.h"

#include "bonus/BasicShieldBonus.h"

#include "../../common/utils/GameUtils.h"

#define EQUIPMENT_POSX 0
#define EQUIPMENT_POSX_OFFSET 20
#define EQUIPMENT_POSY 0
#define EQUIPMENT_POSY_OFFSET 20
#define DEFAULT_BONUS_WIDTH 40
#define DEFAULT_BONUS_HEIGHT 40
#define DEFAULT_BONUS_PADDING 5

#define USER_INFO_DEFAULT_TEXTSIZE 14


UserEquipment::UserEquipment(std::string playerName, Widget *parent):
Widget(EQUIPMENT_POSX,EQUIPMENT_POSY, NULL ,parent, true, Color::MAGENTA){

	this->playerName = playerName;

	parcel->updateHW(0,0);

	this->invisibilidad = NULL;

	initEquipment(SHIP_DEFAULT_LIFE);
}

void UserEquipment::showOn(SDL_Surface* surface) {
	if (equipmentAvailable.empty()) return;

	//Dibujo los Bonus en la lista
	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	Bonus* bonusProcessed = NULL;
	for (it = equipmentAvailable.begin(); it != equipmentAvailable.end(); ++it) {
		bonusProcessed = (*it)->second;
		if(bonusProcessed) bonusProcessed->showOn(surface);
	}

	Widget::showOn(surface);
}


void UserEquipment::drawEquipment(SDL_Surface* surface,int offsetX,int offsetY) {
	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	for (it = equipmentAvailable.begin(); it != equipmentAvailable.end(); ++it) {
		((std::pair<Equipment*,Bonus*>*)*it)->first->showOn(surface,offsetX,offsetY);
	}
}


void UserEquipment::arrangeBonusList(){
	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	int tmpX = EQUIPMENT_POSX_OFFSET;

	it = equipmentAvailable.begin();
	while ( it != equipmentAvailable.end()) {
		Bonus* bonus = ((std::pair<Equipment*,Bonus*>*)*it)->second;
		if(bonus){
			bonus->updatePosicion(tmpX,EQUIPMENT_POSY_OFFSET);

			tmpX += DEFAULT_BONUS_WIDTH;
		}
		it++;
	}


	if(tmpX != EQUIPMENT_POSX_OFFSET){
		parcel->updateHW(DEFAULT_BONUS_HEIGHT,tmpX- EQUIPMENT_POSX_OFFSET);
	}

}

void UserEquipment::resetBonusList(){
	parcel->updateHW(DEFAULT_BONUS_HEIGHT,0);
}

void UserEquipment::addToBonusList(Bonus* newBonus){
	SDL_Rect rectangle = parcel->getRectangle();

	int tmpX = rectangle.w + DEFAULT_BONUS_WIDTH/2;

	//Add the item to the list
	newBonus->updatePosicion(tmpX,DEFAULT_BONUS_HEIGHT/2);

	parcel->updateHW(DEFAULT_BONUS_HEIGHT,rectangle.w + DEFAULT_BONUS_WIDTH + DEFAULT_BONUS_PADDING);
}



void UserEquipment::handleEvent(Event event){
	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	for (it = equipmentAvailable.begin(); it != equipmentAvailable.end(); ++it) {
		((std::pair<Equipment*,Bonus*>*)*it)->first->handleEvent(event);
	}
}

void UserEquipment::addBonus(Bonus* bonus){

	Equipment* equipment = NULL;
	//Nota, no poner default asi al agregarse bonus manda un warning por aca
	switch (bonus->getBonusType()) {
		case BASIC_SHIELD:
			equipment = new EquipmentBasicShield(parent);
			break;
		case SUPER_SHIELD:
			equipment = new EquipmentSuperShield(parent);
			break;
		case MISSILE:
			equipment = new EquipmentMissile(parent);
			break;
		case INVISIBLE:
			equipment = new EquipmentInvisible(parent);
			break;
		case LASER:
			equipment = new EquipmentLaser(parent);
			break;
		case MINA:
			equipment = new EquipmentMina(parent);
			break;
		case COUNT:
		case BULLET:
		case USER_INFO:
			//do nothing...
			break;
	}

	addToEquipment(new std::pair<Equipment*,Bonus*>(equipment,bonus) );

}

void UserEquipment::reduceLife(int value,playElement element){

	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	std::pair<Equipment*,Bonus*>* pairProcessing = NULL;
	for (it = equipmentAvailable.begin(); it != equipmentAvailable.end(); ++it) {
		pairProcessing = (*it);

		value = pairProcessing->first->reduceLife(value,element);
		if(value <= 0) return;

	}
}


void UserEquipment::addToEquipment(std::pair<Equipment*,Bonus*>* pair){
	//Check that its not in the equipment already
	bool alreadyEquiped = false;

	std::list<std::pair<Equipment*,Bonus*>*>::iterator it = equipmentAvailable.begin();
	while (it != equipmentAvailable.end()){

		//ya lo tengo?
		if ((*it)->first->getType() == pair->first->getType()){
			alreadyEquiped = true;
			(*it)->first->updateStatus();

			//Ya lo encontre y actulizo .salir
			break;
		}else{
			if (pair->first->getType() == LASER ){
				//Tengo que borrar las balas
				if((*it)->first->getType() == BULLET){
					if((*it)->second != NULL){
						delete (*it)->second;
					}
					//Delete the equipment from memory
					delete (*it)->first;
					//remover
					it = equipmentAvailable.erase(it);
				}
			}

			if (pair->first->getType() == SUPER_SHIELD ){
				//Tengo que borrar las balas
				if((*it)->first->getType() == BASIC_SHIELD){
					if((*it)->second != NULL){
						delete (*it)->second;
					}
					//Delete the equipment from memory
					delete (*it)->first;
					//remover
					it = equipmentAvailable.erase(it);
				}
			}

			// Si es Super Shield
			if (pair->first->getType() == SUPER_SHIELD ){
				//Tengo que borrar el basic shield
				if((*it)->first->getType() == BASIC_SHIELD){
					if((*it)->second != NULL){
						delete (*it)->second;
					}
					//Delete the equipment from memory
					delete (*it)->first;
					//remover
					it = equipmentAvailable.erase(it);
				}
			}

			// Si es Basic Shield
			if (pair->first->getType() == BASIC_SHIELD ){
				//Me fijo si ya tiene super shield
				if((*it)->first->getType() == SUPER_SHIELD){
					alreadyEquiped = true;
					//Ya tiene super shield; salgo;
					break;
				}
			}
		}

		//Se mueve al siguiente
		it++;
	}


	//If not, just add it
	if(!alreadyEquiped){
		equipmentAvailable.push_back(pair);

		if(pair->second!=NULL){
			addToBonusList(pair->second);
		}
	}

	equipmentAvailable.sort(GameUtils::compareEquipment);
}

std::list<DTOEquipment*>  UserEquipment::getDTO(){
	std::list<DTOEquipment*> list;

	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	for (it = equipmentAvailable.begin(); it != equipmentAvailable.end(); ++it) {
		list.push_back((*it)->first->getDTO());
	}

	return list;
}

void UserEquipment::resolve() {
	std::list< std::pair<Equipment*,Bonus*>* >::iterator it;
	for (it = equipmentAvailable.begin(); it != equipmentAvailable.end(); ++it) {
		if ((*it)->second != NULL){
			(*it)->second->resolve();
		}
	}
	std::list<std::pair<Equipment*,Bonus*>*>::iterator itEquip;
	std::pair<Equipment*,Bonus*>* pairProcessing = NULL;

	itEquip = equipmentAvailable.begin();

	bool erase = false;
	invisibilidad = NULL;
	while(itEquip != equipmentAvailable.end()) {
		pairProcessing = (*itEquip);
		if(pairProcessing->first->isEmpty()){
			SDL_Rect rectangle = parcel->getRectangle();
			if (rectangle.w - (DEFAULT_BONUS_WIDTH + DEFAULT_BONUS_PADDING) >=0){
				parcel->updateHW(DEFAULT_BONUS_HEIGHT,rectangle.w - (DEFAULT_BONUS_WIDTH + DEFAULT_BONUS_PADDING));
			}
			delete(*itEquip);
			itEquip=equipmentAvailable.erase(itEquip);
			erase=true;
		}else{
			//Patch para invisibilidad
			if(pairProcessing->first->getType() == INVISIBLE)
				invisibilidad = (EquipmentInvisible*)pairProcessing->first;

			itEquip++;
		}
	}

	if (erase){
		this->arrangeBonusList();
	}
	Widget::resolve();
}

void UserEquipment::initEquipment(int ship_life){

	//Empty the old equipment
	while(!equipmentAvailable.empty()){
		std::pair<Equipment*,Bonus*>* deleting = equipmentAvailable.front();
		if(deleting->second != NULL){
			delete deleting->second;
		}
		//Delete the equipment from memory
		delete deleting->first;

		delete deleting;
		equipmentAvailable.pop_front();
	}

	//Add default equipment
	//bullets
	Equipment* bullets = new EquipmentBullets(parent);
	equipmentAvailable.push_back(new std::pair<Equipment*,Bonus*>(bullets,NULL) );

	userInfo = new EquipmentUserInfo(playerName,ship_life,parent);
	equipmentAvailable.push_back(new std::pair<Equipment*,Bonus*>(userInfo,NULL) );

	//Dont remove
	equipmentAvailable.sort(GameUtils::compareEquipment);
}

void UserEquipment::updateEquipments(std::list<DTOEquipment*> equipments){
	int ship_life = 0;
	bool hayBasicShield = false;

	std::list<DTOEquipment*>::iterator it;
	for (it = equipments.begin(); it != equipments.end(); ++it) {
		DTOEquipment* equipment = (*it);
		if ((BonusType)equipment->bonusType == USER_INFO) {
				ship_life = equipment->value;
		}

		if ((BonusType)equipment->bonusType == BASIC_SHIELD ) {
			hayBasicShield = true;
		}
	}

	if(!hayBasicShield){
		hayBasicShield = false;
	}

	initEquipment(ship_life);

	for (it = equipments.begin(); it != equipments.end(); ++it) {
		Equipment* equip = NULL;
		DTOEquipment* equipment = (*it);
		//Nota, no poner default asi al agregarse bonus manda un warning por aca
		switch (equipment->bonusType) {
			case BASIC_SHIELD:
				equip = new EquipmentBasicShield(equipment,parent);
				break;
			case SUPER_SHIELD:
				equip = new EquipmentSuperShield(equipment,parent);
				break;
			case MISSILE:
				equip = new EquipmentMissile(equipment,parent);
				break;
			case INVISIBLE:
				equip = new EquipmentInvisible(equipment,parent);
				break;
			case LASER:
				equip = new EquipmentLaser(equipment,parent);
				break;
			case MINA:
				equip = new EquipmentMina(equipment,parent);
				break;
			case COUNT:
			case BULLET:
			case USER_INFO:
				break;
		}

		if(equip != NULL){
			addToEquipment(new std::pair<Equipment*,Bonus*>(equip,NULL));
		}
	}
}


int UserEquipment::getUserLife(){
	return userInfo->getLifePorcent();
}

std::string UserEquipment::getPlayerName(){
	return playerName;
}

UserEquipment::~UserEquipment() {}

EquipmentInvisible *UserEquipment::getInvisibilidad() const
{
    return invisibilidad;
}




